package code.HAOJianguo;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import java.util.Iterator;

import code.Najib.ActivityAgentNetDiscovery;

import client.domainModels.Node.Node;
import client.domainModels.NodeImpl.AbstractNode;
import client.domainModels.NodeImpl.LogFile;
import client.domainModels.NodeImpl.Receiver;

public class DelegationModel {

	private static ArrayList<String> PROPOSAL = new ArrayList<String>() {
		{
                        add("request");
			add("propose");
			
		};
	};
	private static ArrayList<String> REJECT_PROPOSAL = new ArrayList<String>() {
		{
			add("reject");
                        add("refuse");
		};
	};
	private static ArrayList<String> ACCEPT_PROPOSAL = new ArrayList<String>() {
		{
			add("accept");
			add("agree");
		};
	};

	
	/*
	 * This is a container of all the actors and participants. Each agent is
	 * unique.
	 */
	private static ArrayList<String> agents;
	private static ArrayList<String> performatives;

	/**
	 * @author HAO Jianguo This is a function to analyse all the activity of
	 *         contract net protocol.
	 * */
	public static void analyseProposeInteraction(LogFile log) {
		agents = new ArrayList<String>();

		int agentAmount = getAgentAmount(log);
		String[][] interactionMatrix = getProposeInteractionMatrix(log,
				agentAmount);

		// final matrix
		Integer[][] netDrawMatrix = new Integer[agentAmount][agentAmount];

		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				// either element is null -> all of two are not satisfact
				// propose
				if (interactionMatrix[i][j] == null
						|| interactionMatrix[j][i] == null) {
					netDrawMatrix[i][j] = 0;
					netDrawMatrix[j][i] = 0;
				} else {
					// one is propose
					if (PROPOSAL
							.contains(interactionMatrix[i][j].toLowerCase())) {
						// another is accept or reject -> one is satisfact
						// propose
						if (ACCEPT_PROPOSAL.contains(interactionMatrix[j][i]
								.toLowerCase())
								|| REJECT_PROPOSAL
										.contains(interactionMatrix[j][i]
												.toLowerCase())) {
							netDrawMatrix[i][j] = 1;
							netDrawMatrix[j][i] = 0;
						}
						// another is niether accept or reject -> all are not
						// satisfact propose.
						else {
							netDrawMatrix[i][j] = 0;
							netDrawMatrix[j][i] = 0;
						}
						// not propose, but either accept or reject
					} else if (ACCEPT_PROPOSAL.contains(interactionMatrix[i][j]
							.toLowerCase())
							|| REJECT_PROPOSAL.contains(interactionMatrix[i][j]
									.toLowerCase())) {
						// another is propose, one is satisfact propose.
						if (PROPOSAL.contains(interactionMatrix[j][i]
								.toLowerCase())) {
							netDrawMatrix[j][i] = 1;
							netDrawMatrix[i][j] = 0;
						}
						// another is not propose, none is satisfait propose.
						else {
							netDrawMatrix[j][i] = 0;
							netDrawMatrix[i][j] = 0;
						}
						// neither propose, neither accept or reject, none is
						// satisfait propose.
					} else {
						netDrawMatrix[i][j] = 0;
						netDrawMatrix[j][i] = 0;
					}
				}
			}
		}
		createFileVNA(netDrawMatrix, "./propose_interaction.vna");
		createBatchFile("./batch_propose.txt","propose_interaction.vna");
	}

	
	public static ArrayList<String> getPROPOSAL() {
		return PROPOSAL;
	}


	public static void addPROPOSAL(String proposal) {
		PROPOSAL.clear();
		PROPOSAL.add(proposal);
	}


	public static ArrayList<String> getREJECT_PROPOSAL() {
		return REJECT_PROPOSAL;
	}


	public static void addREJECT_PROPOSAL(String reject_proposal) {
		REJECT_PROPOSAL.clear();
		REJECT_PROPOSAL.add(reject_proposal);
	}


	public static ArrayList<String> getACCEPT_PROPOSAL() {
		return ACCEPT_PROPOSAL;
	}


	public static void addACCEPT_PROPOSAL(String accept_proposal) {
		ACCEPT_PROPOSAL.clear();
		ACCEPT_PROPOSAL.add(accept_proposal);
	}


	public static void anaylseActorInCase(LogFile log) {
		agents = new ArrayList<String>();

		// Integer[][] netDrawMatrix=
	}

	// public static void anaylseActorInCase(LogFile log) {
	// agents = new ArrayList<String>();
	// cases = new ArrayList<String>();
	// performatives = new ArrayList<String>();
	//
	// int agentAmount = getAgentAmount(log);
	// int caseAmount = getCaseAmount(log);
	// int indexCase = 0;
	// Integer[][] netDrawMatrix = new Integer[agentAmount][caseAmount];
	//
	// String[] nodes = log.getChildNodeNames();
	// // Part 2 - analyse the matrix of delegate
	// // Get leaves nodes of root node.
	// for (int i = 0; i < nodes.length; i++) {
	// // name of root node's leaves nodes.
	// String root_leaf = nodes[i];
	// // get cases - root node's leaves nodes.
	// ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
	// // iterate cases and get his leaves nodes'object.
	// for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
	// // get each event - cases' leaves nodes object.
	// Node case_ = ii.next();
	// indexCase = OrganisationalModel.cases.indexOf(case_.getID());
	// ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
	// "Event");
	// for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
	// Node event = iii.next();
	// // get actor, receivers - event's leaves nodes.
	// ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
	// .get("Actor");
	// ArrayList<AbstractNode> performative = event
	// .getChildNames_childObjs().get("Performative");
	// ArrayList<AbstractNode> receiverss = event
	// .getChildNames_childObjs().get("Receivers");
	// ArrayList<AbstractNode> receivers = receiverss.get(0)
	// .getChildNames_childObjs().get("Receiver");
	//
	// // get actor index in the array.
	// String actorID = actors.get(0).getID();
	// int indexOfActor = agents.indexOf(actorID);
	// // complete matrix by the index of actor and index of case.
	// if (netDrawMatrix[indexOfActor][indexCase] != null) {
	// netDrawMatrix[indexOfActor][indexCase] += 1;
	// } else {
	// netDrawMatrix[indexOfActor][indexCase] = 1;
	// }
	// }
	// }
	// }
	// }

	// public static void anaylseActorByPerformative(LogFile log) {
	// agents = new ArrayList<String>();
	// cases = new ArrayList<String>();
	// performatives = new ArrayList<String>();
	//
	// }

	private static int getAgentAmount(LogFile log) {
		int agentAmount = 0;
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<AbstractNode> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					// The collection (agents) of actor and receivers is empty
					// or
					// not
					String actorID = actors.get(0).getID();
					if (agents.isEmpty()) {
						// add actor to the collection
						agents.add(actorID);
					} else {
						if (!agents.contains(actorID)) {
							agents.add(actorID);
						}
					}
					// add each receiver to the collection
					ArrayList<AbstractNode> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						if (!agents.contains(receiverName)) {
							agents.add(receiverName);
						}
					}
				}
			}
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		agentAmount = agents.size();
		return agentAmount;
	}



	// public static int getPerformatifAmount(LogFile log) {
	// int caseAmount = 0;
	// String[] nodes = log.getChildNodeNames();
	// // Get leaves nodes of root node.
	// for (int i = 0; i < nodes.length; i++) {
	// // name of root node's leaves nodes.
	// String root_leaf = nodes[i];
	// // get cases - root node's leaves nodes.
	// ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
	// // iterate cases and get his leaves nodes'object.
	// for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
	// // get each event - cases' leaves nodes object.
	// Node case_ = ii.next();
	// ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
	// "Event");
	// for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
	// Node event = iii.next();
	// // get actor, receivers - event's leaves nodes.
	// ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
	// .get("Actor");
	// ArrayList<AbstractNode> performative = event
	// .getChildNames_childObjs().get("Performative");
	// // The collection (agents) of actor and receivers is empty
	// // or
	// // not
	// String actorID = actors.get(0).getID();
	// if (agents.isEmpty()) {
	// // add actor to the collection
	// agents.add(actorID);
	// } else {
	// if (!agents.contains(actorID)) {
	// agents.add(actorID);
	// }
	// }
	// // add each receiver to the collection
	// ArrayList<AbstractNode> receivers = receiverss.get(0)
	// .getChildNames_childObjs().get("Receiver");
	// for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
	// .hasNext();) {
	// Node receiver = iiii.next();
	// String receiverName = receiver.getID();
	// if (!agents.contains(receiverName)) {
	// agents.add(receiverName);
	// }
	// }
	// }
	// }
	// caseAmount = cases.size();
	// }
	// // create a matrix and the size of matrix is amount of agent * amount of
	// // agent.
	// return caseAmount;
	// }

	/**
	 * This foncion will get a matrix which contains all the interaction in the
	 * file log. Each line of the matrix is an actor, and each row of the matrix
	 * is a receiver.
	 * 
	 * @author HAO Jianguo
	 * @param log
	 *            The object of LogFile to analyse.
	 * @param agentAmount
	 *            The amount of agent(actor, participant).
	 * @return interactionMatrix The matrix which contains all the interaction
	 *         in the file log.
	 * */
	private static String[][] getProposeInteractionMatrix(LogFile log,
			int agentAmount) {
		String[][] interactionMatrix = new String[agentAmount][agentAmount];
		String[] nodes = log.getChildNodeNames();
		// Part 2 - analyse the matrix of delegate
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<AbstractNode> performative = event
							.getChildNames_childObjs().get("Performatif");
					ArrayList<AbstractNode> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					ArrayList<AbstractNode> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					// The collection (agents) of actor and receivers is empty
					// or not
					String actorID = actors.get(0).getID();
					int indexOfActor = agents.indexOf(actorID);

					// iterate each receiver to the collection
					for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						int indexOfReceiver = agents.indexOf(receiverName);
						interactionMatrix[indexOfActor][indexOfReceiver] = performative
								.get(0).getID();
					}
				}
			}
		}
		return interactionMatrix;
	}

	

	/**
	 * This fonction will create a VNA file to be used in NetDraw
	 * 
	 * @author HAO Jianguo
	 * */
	public static void createFileVNA(Integer[][] matrix, String filePath) {
		File pointVNA = new File(filePath);
		try {
			FileWriter fw = new FileWriter(pointVNA);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("*Node data" + "\n");
			bw.write("*Node properties" + "\n");
			bw.write("*Tie data" + "\n");
			bw.write("ACTOR RECEIVER \"" + "Propose Interaction" + "\"" + "\n");
			for (int i = 0; i < matrix.length; i++) {
				for (int j = 0; j < matrix.length; j++) {
					if (matrix[i][j] == 1) {
						String actor = agents.get(i);
						String receiver = agents.get(j);
						bw.write("\"" + actor + "\"");
						bw.write(" ");
						bw.write("\"" + receiver + "\"");
						bw.write(" ");
						bw.write("1");
						bw.write("\n");
					}
				}
			}
			bw.flush();
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static ArrayList<String> getPerformatif(LogFile log) {
		performatives = new ArrayList<String>();
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<AbstractNode> performatif = event
							.getChildNames_childObjs().get("Performative");
					// The collection (agents) of actor and receivers is empty
					// or
					// not
					String performative = performatif.get(0).getID();
					if (performatives.isEmpty()) {
						// add actor to the collection
						performatives.add(performative);
					} else {
						if (!performatives.contains(performative)) {
							performatives.add(performative);
						}
					}
				}
			}
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		return performatives;
	}
	
	public static void createBatchFile(String filePath, String vnaName) {
		File pointBatch = new File(filePath);
//		String nameOfFile = "";
//		if (filePath.contains("/")) {
//			StringTokenizer st = new StringTokenizer(filePath, "/");
//
//			while (st.hasMoreTokens()) {
//				nameOfFile = st.nextToken();
//			}
//		} else if (filePath.contains("\\")) {
//			StringTokenizer st = new StringTokenizer(filePath, "\\");
//			while (st.hasMoreTokens()) {
//				nameOfFile = st.nextToken();
//			}
//		}

		try {
			FileWriter fw = new FileWriter(pointBatch);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("Loadvna " + vnaName + "\n");
			bw.write("runlayout" + "\n");
			bw.flush();
                        bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
